package job

import (
	"context"
	"fmt"
	"gcrontab/common"
	"github.com/coreos/etcd/clientv3"
	"time"
)

//初始化etcd

type Register struct {
	client  *clientv3.Client
	kv      clientv3.KV
	lease   clientv3.Lease
	watcher clientv3.Watcher
}

var G_register *Register

//etcd连接初始化
func InitRegister() (err error) {
	//初始化配置
	config := clientv3.Config{
		Endpoints:   common.G_conifg.EtcdEndpoints,
		DialTimeout: time.Duration(common.G_conifg.EtcdDialTimeout) * time.Millisecond,
	}
	//建立连接
	cli, err := clientv3.New(config)
	if err != nil {
		return err
	}
	kv := clientv3.NewKV(cli)
	lease := clientv3.Lease(cli)
	watcher := clientv3.NewWatcher(cli)
	//赋值单例
	G_register = &Register{
		client:  cli,
		kv:      kv,
		lease:   lease,
		watcher: watcher,
	}
	fmt.Println("keeponline")
	G_register.keepOnLine()
	return
}

//实时检测 etcd
func (r *Register) keepOnLine() () {
	var (
		leaseGrantResp *clientv3.LeaseGrantResponse
		localIp        string
		err            error
		ctx            context.Context
		cancelFunc     context.CancelFunc
		leaseId        clientv3.LeaseID
		keepRespChan   <-chan *clientv3.LeaseKeepAliveResponse
		keepResp       *clientv3.LeaseKeepAliveResponse
	)
	for {
		//获取local IP
		//localIp, err = common.GetLocalIp()
		//if err != nil {
		//	goto RETRY
		//}

		localIp = common.GetRand()

		fmt.Println("ip:", localIp)
		cancelFunc = nil

		//1，创建租约 5s， 类似于5s一次心跳
		leaseGrantResp, err = r.lease.Grant(context.TODO(), 5)
		if err != nil {
			goto RETRY
		}
		leaseId = leaseGrantResp.ID //租约ID

		//2，创建cancelFunc 用于取消自动续租
		ctx, cancelFunc = context.WithCancel(context.TODO())

		//3，自动续租
		keepRespChan, err = r.lease.KeepAlive(ctx, leaseId)
		if err != nil {
			goto RETRY
		}

		//4，注册到etcd
		_, err = r.kv.Put(ctx, common.REGISTER_DIR+localIp, "", clientv3.WithLease(leaseId))
		if err != nil {
			goto RETRY
		}

		//5，处理自动续约应答。阻塞于此处
		for {
			select {
			case keepResp = <-keepRespChan:
				if keepResp == nil {
					fmt.Printf("register 关闭续租\n")
					goto RETRY
				}
			}
		}
	RETRY:
		time.Sleep(1 * time.Second) //todo 一直失败，一直尝试？
		if cancelFunc != nil {
			cancelFunc()                            //取消自动续租
			r.lease.Revoke(context.TODO(), leaseId) //立即释放租约
		}
	}
}
